# Copyright (c) 2006-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Steve Reinhardt
# 	   Gou Pengfei

import os
import optparse
import sys
from os.path import join as joinpath

import m5
from m5.defines import buildEnv
from m5.objects import *
from m5.util import addToPath, fatal


if buildEnv['FULL_SYSTEM']:
    fatal("This script requires syscall emulation mode (*_SE).")

config_root = joinpath(os.environ['HOME'], 'M5-EDGE', 'configs')

addToPath(joinpath(config_root, 'common'))

import Simulation
from Caches import *
from cpu2000 import *

# This is the name of this configuration. This should be the same as name of this file
conf = ((os.path.basename(sys.argv[0])).split('.'))[0]

# Get paths we might need.  It's expected this file is in m5/configs/example.
config_path = os.path.dirname(os.path.abspath(__file__))
config_root = os.path.dirname(config_path)
m5_root = os.path.dirname(config_root)
simple_bench_dir = os.environ.get('simplebench',
                                  joinpath(os.environ['HOME'], 'ttools2-devel/bin/'))

parser = optparse.OptionParser()

execfile(os.path.join(config_root, "common", "Options.py"))

(options, args) = parser.parse_args()

# Define Cache Class
class MyCache(BaseCache):
    assoc = 2
    block_size = 64
    latency = '1ps'
    mshrs = 64
    tgts_per_mshr = 5

# Define CPU, system and Memory Hierarchy
cpu = SimpleEdgeCPU(cpu_id = 0,
		    numThreads = 1,
		    numIQEntries = 1024,
		    exitPredType = 'TargetOnly',
                    btypePredType = 'Twostage',
                    btypeTwostagePredictionMode = 'PerfectSeqAndHyst',
                    globalPredictorSize = 4096,
		    SQEntries = 256,
		    LQEntries = 256,
                    preExecuteMode = True,
                    simPointSim = False,
                    memDepMode = 'Perfect',
                    predicationMode = 'Perfect')
##CONFIG
cpu.btbType = 'NewBTB';
cpu.BTBIndexType = 'PredicationHistory';
cpu.BTBTableMode = 'AliasFree';

cpu.BTBEntries = 4096;
cpu.CTBEntries = 128;
cpu.RASSize = 128;

cpu.addTwoLevelCacheHierarchy(MyCache(size='256kB'), MyCache(size='256kB'), MyCache(size='2MB'))

cpu.toL2Bus.clock = '1THz'
                              
cpu.clock = '2GHz'

system = System(cpu = cpu,
                physmem = PhysicalMemory(latency = '1ps',range = AddrRange(Addr('0MB'), size = '256MB')),
                membus = Bus(clock='1THz'),
                mem_mode = 'atomic')

system.physmem.port = system.membus.port
cpu.connectMemPorts (system.membus)

# Define pre execute cpu and its system.
p_cpu = AtomicEdgeCPU(cpu_id = 0,
                      maxPass = 256,
                      preExecuteMode = True,
                      simPointSim = False)
                              
p_cpu.clock = cpu.clock

p_system = System(cpu = p_cpu,
                  physmem = PhysicalMemory(latency = '1ps',range = AddrRange(Addr('0MB'), size = '256MB')),
                  membus = Bus(clock='1THz'),
                  mem_mode = 'atomic')

p_system.cpu.physmem_port = p_system.physmem.port

p_system.physmem.port = p_system.membus.port
p_cpu.connectMemPorts(p_system.membus)

cpu.preExecuteCPU = p_cpu

root = Root(system = [system,p_system])

# Since we're in batch mode, dont allow tcp socket connections
m5.disableAllListeners()

# set default maxtick... script can override
# -1 means run forever
maxtick = m5.MaxTick

       
if options.simplebench:
    try:
        process0 = LiveProcess(cmd = options.simplebench,
                               env = ['phoenix','fairy'],
                               executable = os.path.join(simple_bench_dir, options.simplebench))
        process1 = LiveProcess(cmd = options.simplebench,
                               env = ['phoenix','fairy'],
                               executable = os.path.join(simple_bench_dir, options.simplebench))
    except:
        print>> sys.stderr, "Unable to find worload for %s" % options.simplebench
        sys.exit(1)
        
# tweak configuration for specific test
root.system[0].cpu.workload = process0

from m5.main import options

process0.output = joinpath(options.outdir, 'output')
process0.errout = joinpath(options.outdir, 'errout')
process1.output = joinpath(options.outdir, 'pre-output')
process1.errout = joinpath(options.outdir, 'pre-errout')

root.system[1].cpu.workload = process1

# instantiate configuration
m5.instantiate(root)

from m5.stats import *

# simulate until program terminates
exit_event = m5.simulate(maxtick)

print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
